﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Security.Cryptography;
using System.Net.Json;

public class Utility
{
    static DateTime BaseDateTime = new DateTime(1970, 1, 1, 0, 0, 0);

    public static String RenderJson(object obj)
    {
        StringBuilder builder = new StringBuilder();
        RenderJson(builder, obj);
        return builder.ToString();
    }

    public static void RenderJson(StringBuilder builder, object obj)
    {
        if (obj is IRenderJson)
        {
            (obj as IRenderJson).RenderJson(builder);
        }
        else if (obj is Exception)
        {
            builder.AppendFormat("{{\"__DataType\":\"Exception\",\"__Value\":{{\"Name\":\"{0}\",\"Message\":\"{1}\"}}}}", obj.GetType().Name, Utility.TransferCharJavascript((obj as Exception).Message));
        }
        else if (obj.GetType() == typeof(DateTime))
        {
            DateTime val = (DateTime)obj;
            RenderHashJson(
                builder,
                "__DataType", "Date",
                "__Value", (val - BaseDateTime).TotalMilliseconds
            );
        }
        else if (obj is IDictionary)
        {
            int count = 0;
            builder.Append("{");
            foreach (DictionaryEntry ent in (obj as IDictionary))
            {
                if (count > 0) builder.Append(",");
                builder.AppendFormat("\"{0}\":", Utility.TransferCharJavascript(ent.Key.ToString()));
                RenderJson(builder, ent.Value);
                count++;
            }
            builder.Append("}");
        }
        else if (obj is IList)
        {
            IList list = obj as IList;
            builder.Append("[");
            for (int i = 0; i < list.Count; i++)
            {
                if (i > 0) builder.Append(",");
                RenderJson(builder, list[i]);

            }
            builder.Append("]");
        }
        else if (obj is ICollection)
        {
            ICollection list = obj as ICollection;
            builder.Append("[");
            int count = 0;
            foreach (object val in list)
            {
                if (count > 0) builder.Append(",");
                RenderJson(builder, val);
                count++;
            }
            builder.Append("]");
        }
        else if (obj is DataRow)
        {
            DataRow row = obj as DataRow;
            builder.Append("{");

            int count = 0;
            foreach (DataColumn column in row.Table.Columns)
            {
                if (count > 0) builder.Append(",");
                builder.AppendFormat("\"{0}\":", column.ColumnName);
                RenderJson(builder, row[column.ColumnName]);
                count++;
            }

            builder.Append("}");
        }
        else if (obj is UInt16 || obj is UInt32 || obj is UInt64 || obj is Int16 || obj is Int32 || obj is Int64 || obj is Double || obj is Decimal || obj is long)
        {
            builder.Append(obj.ToString());
        }
        else if (obj is System.Drawing.Rectangle)
        {
            System.Drawing.Rectangle rect = (System.Drawing.Rectangle)obj;

            RenderHashJson(
                builder,
                "Left", rect.Left,
                "Top", rect.Top,
                "Width", rect.Width,
                "Height", rect.Height
            );
        }
        else if (obj is bool)
        {
            builder.Append((bool)obj ? "true" : "false");
        }
        else
        {
            builder.Append("\"");
            builder.Append(TransferCharJavascript(obj.ToString()));
            builder.Append("\"");
        }
    }

    public static String RenderHashJson(params object[] ps)
    {
        StringBuilder builder = new StringBuilder();
        builder.Append("{");
        for (int i = 0; i < ps.Length; i += 2)
        {
            if (i > 0) builder.Append(",");
            builder.AppendFormat("\"{0}\":", ps[i].ToString());
            RenderJson(builder, ps[i + 1]);
        }
        builder.Append("}");
        return builder.ToString();
    }

    public static void RenderHashJson(StringBuilder builder, params object[] ps)
    {
        builder.Append("{");
        for (int i = 0; i < ps.Length; i += 2)
        {
            if (i > 0) builder.Append(",");
            builder.AppendFormat("\"{0}\":", ps[i].ToString());
            RenderJson(builder, ps[i + 1]);
        }
        builder.Append("}");
    }

    public static string TransferCharJavascript(string s)
    {
        StringBuilder ret = new StringBuilder();
        foreach (char c in s)
        {
            switch (c)
            {
                case '\r':
                case '\t':
                case '\n':
                case '\f':
                case '\v':
                case '\"':
                case '\\':
                case '\'':
                case '<':
                case '>':
                case '\0':
                    ret.AppendFormat("\\u{0:X4}", (int)c);
                    break;
                default:
                    ret.Append(c);
                    break;
            }
        }
        return ret.ToString();
    }

    public static string TransferCharForXML(string s)
    {
        StringBuilder ret = new StringBuilder();
        foreach (char c in s)
        {
            switch (c)
            {
                case '\r':
                case '\t':
                case '\n':
                case '\f':
                case '\v':
                case '\"':
                case '\\':
                case '\'':
                case '<':
                case '>':
                    ret.AppendFormat("&#{0};", (int)c);
                    break;
                default:
                    ret.Append(c);
                    break;
            }
        }
        return ret.ToString();
    }

    public static string Decode(string s)
    {
        Regex r = new Regex("\\\\u[0-9a-fA-F]{4}|\\\\x[0-9a-fA-F]{2}");
        MatchEvaluator eval = new MatchEvaluator(ReplaceChar);
        return r.Replace(s, eval);
    }

    public static string ReplaceChar(Match match)
    {
        ushort ascii;
        if (match.Length == 4)
        {
            ascii = ushort.Parse(match.Value.Substring(2, 2), NumberStyles.HexNumber);
        }
        else
        {
            ascii = ushort.Parse(match.Value.Substring(2, 4), NumberStyles.HexNumber);
        }
        char c = Convert.ToChar(ascii);
        return c.ToString();
    }

    public static string MD5(string str)
    {
        MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
        byte[] data = md5.ComputeHash(UTF8Encoding.Default.GetBytes(str));
        StringBuilder sBuilder = new StringBuilder();
        for (int i = 0; i < data.Length; i++)
        {
            sBuilder.Append(data[i].ToString("X2"));
        }
        return sBuilder.ToString();
    }

    public static Object ParseJson(string jsonText)
    {
        if (!string.IsNullOrEmpty(jsonText))
        {
            JsonTextParser parser = new JsonTextParser();
            JsonObject obj = parser.Parse(jsonText);
            return ParseJson(obj);
        }
        else
        {
            return null;
        }
    }

    private static Object ParseJson(JsonObject jsonObject)
    {
        Type type = jsonObject.GetType();
        if (type == typeof(JsonObjectCollection))
        {
            Hashtable val = new Hashtable();
            foreach (JsonObject subObj in (jsonObject as JsonObjectCollection))
            {
                val.Add(subObj.Name, ParseJson(subObj));
            }
            if (val.ContainsKey("__DataType"))
            {
                if (val["__DataType"] as string == "Date")
                {
                    return BaseDateTime.AddMilliseconds((Double)val["__Value"]);
                }
                else
                {
                    return val;
                }
            }
            else
            {
                return val;
            }
        }
        else if (type == typeof(JsonArrayCollection))
        {
            List<object> val = new List<object>();
            foreach (JsonObject subObj in (jsonObject as JsonArrayCollection))
            {
                val.Add(ParseJson(subObj));
            }
            return val.ToArray();
        }
        else if (type == typeof(JsonBooleanValue))
        {
            return jsonObject.GetValue();
        }
        else if (type == typeof(JsonStringValue))
        {
            return jsonObject.GetValue();
        }
        else if (type == typeof(JsonNumericValue))
        {
            return jsonObject.GetValue();
        }
        else
            return null;
    }
}

public interface IRenderJson
{
    void RenderJson(StringBuilder builder);
}

public class JsonText : IRenderJson
{
    static JsonText m_EmptyObject = new JsonText("{}");

    static public JsonText EmptyObject
    {
        get { return m_EmptyObject; }
    }

    static JsonText m_EmptyArray = new JsonText("[]");

    static public JsonText EmptyArray
    {
        get { return m_EmptyArray; }
    }

    String m_Value;

    public JsonText(String value)
    {
        m_Value = value;
    }

    void IRenderJson.RenderJson(StringBuilder builder)
    {
        builder.Append(m_Value);
    }
}